package com.party.admin.biz.analysis;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.party.admin.web.dto.output.analysis.StatisticalFunnelOutput;
import com.party.common.utils.BigDecimalUtils;
import com.party.core.model.analysis.StatisticsEventFlow;
import com.party.core.model.analysis.StatisticsFunnelCounter;
import com.party.core.model.analysis.StatisticsFunnelFlow;
import com.party.core.service.analysis.IStatisticsEventFlowService;
import com.party.core.service.analysis.IStatisticsFunnelCountService;
import com.party.core.service.analysis.IStatisticsFunnelFlowService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 漏斗分析
 *
 * @author yifeng
 * @date 2018/8/10 0010
 * @time 上午 10:12
 */
@Service
public class StatisticalFunnelBizService {
    @Autowired
    private IStatisticsFunnelFlowService statisticsFunnelFlowService;
    @Autowired
    private IStatisticsEventFlowService statisticsEventFlowService;
    @Autowired
    private IStatisticsFunnelCountService statisticsFunnelCountService;

    Logger logger = LoggerFactory.getLogger(getClass());

    public List<StatisticalFunnelOutput> webListPage2(List<Map<String, Object>> flowDatas, Map<String, Object> params) {
        List<StatisticalFunnelOutput> funnelOutputs = Lists.newArrayList();
        List<StatisticsFunnelCounter> counterList = statisticsFunnelCountService.findByFunnelFlowId(params);
        // 第一步
        Integer beginPv = 0;
        // 上一步
        Integer lastPv = 0;
        for (int i = 0; i < counterList.size(); i++) {
            StatisticsFunnelCounter counter = counterList.get(i);

            double lastConvert = 0d;
            double totalConvert = 0d;
            if (i == 0) {
                beginPv = counter.getEventNum();
                if (beginPv > 0) {
                    // 如果是第一步。默认为100%
                    lastConvert = 100d;
                    totalConvert = 100d;
                }
            } else {
                if (lastPv > 0) {
                    double sub = BigDecimalUtils.div(counter.getEventNum(), lastPv);
                    double round = BigDecimalUtils.round(sub, 2);
                    lastConvert = BigDecimalUtils.mul(round, 100);

                    if (beginPv > 0) {
                        double beginSub = BigDecimalUtils.div(counter.getEventNum(), beginPv);
                        double beginRound = BigDecimalUtils.round(beginSub, 2);
                        totalConvert = BigDecimalUtils.mul(beginRound, 100);
                    }
                }
            }

            StatisticalFunnelOutput funnelOutput = new StatisticalFunnelOutput();
            funnelOutput.setName(counter.getFunnelFlowName());
            funnelOutput.setUv(counter.getUserNum());
            funnelOutput.setPv(counter.getEventNum());
            funnelOutput.setLastConvert(lastConvert);
            funnelOutput.setTotalConvert(totalConvert);

            funnelOutputs.add(funnelOutput);

            Map<String, Object> map = Maps.newHashMap();
            map.put("lastConvert", lastConvert);
            map.put("currentPv", counter.getEventNum());
            map.put("name", counter.getFunnelFlowName());
            flowDatas.add(map);

            lastPv = counter.getEventNum();
        }
        return funnelOutputs;
    }

    public List<StatisticalFunnelOutput> webListPage(String funnelId, List<String> flowNames,
                                                     List<Map<String, Object>> flowDatas, Map<String, Object> params) {
        List<StatisticsFunnelFlow> funnelFlows = statisticsFunnelFlowService.findByFunnelId(funnelId);
        List<StatisticalFunnelOutput> funnelOutputs = Lists.newArrayList();
        List<String> middleEvents = new LinkedList<>();
        Long beginPv = 0L; // 第一步
        Long lastPv = 0L; // 上一个
        for (StatisticsFunnelFlow funnelFlow : funnelFlows) {
            Long currentPv = 0L; // 当前Pv
            Long currentUv = 0L; // 当前Uv
            Map<String, Object> newParams = Maps.newHashMap();
            newParams.putAll(params);
            newParams.put("middleEvents", middleEvents);

            flowNames.add(funnelFlow.getName());
            Set<String> userSet = Sets.newHashSet();
            List<StatisticsEventFlow> eventFlows = statisticsEventFlowService.findByEventId(funnelFlow.getEventId(), newParams);
            if (new Integer(1).equals(funnelFlow.getStep()) || middleEvents.size() == 1) {
                for (StatisticsEventFlow eventFlow : eventFlows) {
                    userSet.add(eventFlow.getUserId());
                }
                currentPv = Long.valueOf(eventFlows.size());
                currentUv = Long.valueOf(userSet.size());
            } else {
                for (StatisticsEventFlow eventFlow : eventFlows) {
                    String parentIds = eventFlow.getParentIds();
                    String[] split = parentIds.split(",");
                    int[] positions = new int[middleEvents.size()];
                    for (int j = 0; j < middleEvents.size(); j++) {
                        for (int i = 0; i < split.length; i++) {
                            if (middleEvents.get(j).equals(split[i])) {
                                positions[j] = i;
                                break;
                            }
                        }
                    }

                    boolean isOk = true;
                    //外层循环控制排序趟数
                    for (int i = 0; i < positions.length - 1; i++) {
                        //内层循环控制每一趟排序多少次
                        for (int j = 0; j < positions.length - 1 - i; j++) {
                            if (positions[j] > positions[j + 1]) {
                                isOk = false;
                                break;
                            }
                        }
                    }
                    if (isOk) {
                        userSet.add(eventFlow.getUserId());
                        currentUv = Long.valueOf(userSet.size());
                        currentPv++;
                    }
                    System.out.println();
                }
            }

            if (new Integer(1).equals(funnelFlow.getStep())) {
                beginPv = currentPv;
            }

            middleEvents.add(funnelFlow.getEventId());

            StatisticalFunnelOutput funnelOutput = new StatisticalFunnelOutput();
            funnelOutput.setName(funnelFlow.getName());
            funnelOutput.setUv(currentUv.intValue());
            funnelOutput.setPv(currentPv.intValue());

            Map<String, Object> map = Maps.newHashMap();
            if (!new Integer(1).equals(funnelFlow.getStep())) {
                if (lastPv == 0) {
                    funnelOutput.setLastConvert((double) 0);
                    funnelOutput.setTotalConvert((double) 0);
                } else {
                    double sub = BigDecimalUtils.div(currentPv, lastPv);
                    double round = BigDecimalUtils.round(sub, 2);
                    round = BigDecimalUtils.mul(round, 100);
                    funnelOutput.setLastConvert(round);

                    if (beginPv == 0) {
                        funnelOutput.setTotalConvert((double) 0);
                    } else {
                        double beginSub = BigDecimalUtils.div(currentPv, beginPv);
                        double beginRound = BigDecimalUtils.round(beginSub, 2);
                        beginRound = BigDecimalUtils.mul(beginRound, 100);
                        funnelOutput.setTotalConvert(beginRound);
                    }
                }
            } else {
                if (beginPv == 0) {
                    funnelOutput.setLastConvert((double) 0);
                    funnelOutput.setTotalConvert((double) 0);
                } else {
                    funnelOutput.setLastConvert((double) 100);
                    funnelOutput.setTotalConvert((double) 100);
                }
            }
            funnelOutputs.add(funnelOutput);

            map.put("lastConvert", funnelOutput.getLastConvert());
            map.put("currentPv", currentPv);
            map.put("name", funnelFlow.getName());
            flowDatas.add(map);
            lastPv = currentPv;
        }
        return funnelOutputs;
    }
}
